﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using DynamicToolkit;
using System.Xml;
using DynamicToolkit.Tests.Mocks;
using System.Linq.Expressions;

namespace DynamicToolkit.Tests
{
    [TestClass]
    public class SamplesTest
    {
        [TestMethod]
        public void Samples()
        {
            dynamic addressBook = DynamicXpath.LoadXml(@"
<Phonebook>
  <Contacts>
    <Contact>
      <Name>Tony</Name>
      <Phone Tag='office'>555-111-1111</Phone>
    </Contact>
    <Contact>
      <Name>Steph</Name>
      <Phone Tag='mobile'>555-222-2222</Phone>
    </Contact>
    <Contact>
      <Name>Sam</Name>
      <Phone Tag='school'>555-333-3333</Phone>
      <Phone Tag='mobile'>555-333-4444</Phone>
    </Contact>
  </Contacts>
</Phonebook>
");

            // If you intend to use lambda expressions, you'll need to declare an IPerson interface to 
            // work around some C# limitations.

            // Resolves to: "/*/Contacts/Contact[Name = 'Tony']/Phone[1]/text()"
            string tonyPhoneNumber = addressBook.Contacts.Contact[new { Name = "Tony" }].Phone;

            // Resolves to: "/*/Contacts/Contact[Name = 'Tony']/Phone[1]/text()"
            string tonyPhoneNumber4 = addressBook.Contacts.Contact["Name = 'Tony'"].Phone;
            string tonyPhoneNumber5 = addressBook.Contacts.Contact["Name = 'Tony'"].Phone.Value();
            string tonyPhoneNumber6 = addressBook.Contacts.Contact["Name = 'Tony'"].Phone[0].Value();

            // Resolves to: "/*/Contacts/Contact[Name = 'Steph']/Phone[1]/text()"
            // Currently not in supported in C# 4.0
            // C# 4.0 does not support operations on dynamic types in Expression<TDelegate>
            //string stephPhoneNumber = addressBook.Contacts.Contact[() => p.Name == 'Steph'].Phone;
            //string stephPhoneNumber2 = addressBook.Contacts.Contact[p => p.Name == 'Steph'].Phone.Value();

            // Resolves to: "/*/Contacts/Contact[Name = 'Steph']/Phone[1]/text()"
            // Workaround for the above C# 4.0 limitation using IPerson interface and declaring Expression outside of dynamic object
            Expression<Func<IPerson, bool>> nameEqualsSteph = (p) => p.Name == "Steph";
            string stephPhoneNumber3 = addressBook.Contacts.Contact[nameEqualsSteph].Phone;

            // Resolves to: "/*/Contacts/Contact[Name = 'Steph']/Phone[1]/text()"
            // Currently not in supported in C# 4.0
            //List<string> tonyAndStephsPhoneNumbers = addressBook.Contacts.Contact[p => p.Name == "Tony" || p.Name == 'Steph'].Phone;

            // Resolves to: "/*/Contacts/Contact[Name = 'Tony' and Phone = '555-111-1111'][1]/text()"
            XmlNode tonyWithPhoneNumber = addressBook.Contacts.Contact[new { Name = "Tony", Phone = "555-111-1111" }];

            // Resolves to: "/*/Contacts/Contact[Name = 'Tony' or Name = 'Steph']/Phone/text()"
            List<string> tonyAndStephsPhoneNumbers = addressBook.Contacts.Contact[new { Name = "Tony" }, new { Name = "Steph" }].Phone;

            // Resolves to: "/*/Contacts/Contact[(Name = 'Tony' and Phone = '555-111-1111') or Name = 'Sam']/Phone/text()"
            List<string> tonyAndSamsPhoneNumbers = addressBook.Contacts.Contact[new { Name = "Tony", Phone = "555-111-1111" }, new { Name = "Sam" }].Phone;

            // Resolves to: "/*/Contacts/Contact[Name = 'Tony' or Name = 'Steph']/Phone[1]/text()"
            // Workaround for the above C# 4.0 limitation.  We use a helper interface (IPerson) to get around some of the limitations.
            // String comparisions (greater than, less than, ...) are supported via the DynamicTools.ComparableString class.
            // There is speculation that C# will support extension operator overloading in a future version.
            Expression<Func<IPerson, bool>> nameEqualsTonyOrSteph = (p) => p.Name == "Tony" || p.Name == "Steph";
            List<string> tonyAndStephsPhoneNumbers2 = addressBook.Contacts.Contact[nameEqualsTonyOrSteph].Phone;

            // Resolves to: "/*/Contacts/Contact/Phone"
            XmlNodeList allPhoneNumberNodes = addressBook.Contacts.Contact.Phone;

            // Resolves to: "/*/Contacts/Contact/Phone/text()"
            List<string> allPhoneNumbers = addressBook.Contacts.Contact.Phone;
            IEnumerable<string> allPhoneNumbers2 = addressBook.Contacts.Contact.Phone.Values();

            // Resolves to: "/*/Contacts/Contact[1]"
            XmlNode firstContact = addressBook.Contacts.Contact;
            XmlNode firstContact2 = addressBook.Contacts.Contact.Node();
            XmlNode firstContact3 = addressBook.Contacts.Contact[0].Node();

            // Resolves to: "/*/Contacts/Contact/Phone[@Tag = 'mobile']/text()"
            List<string> mobilePhoneNumbers = addressBook.Contacts.Contact.Phone[new AttributeExample(new { Tag = "mobile" })];

            // Resolves to: "/*/Contacts/Contact[Name = 'Tony']/Phone[1]/@Tag"
            string phoneTag = addressBook.Contacts.Contact["Name = 'Tony'"].Phone.Attribute("Tag");

            // Enumerating over the dynamic XPath
            foreach (dynamic contact in addressBook.Contacts.Contact)
            {
                Console.WriteLine(contact.Name);
            }
        }
    }
}
